/**
 * 通用工具函数
 */

/**
 * 延迟执行
 * @param ms 延迟时间（毫秒）
 */
export const sleep = (ms: number): Promise<void> => {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

/**
 * 防抖函数
 * @param func 要防抖的函数
 * @param wait 等待时间（毫秒）
 */
export const debounce = <T extends (...args: any[]) => any>(
  func: T,
  wait: number,
): ((...args: Parameters<T>) => void) => {
  let timeout: ReturnType<typeof setTimeout> | null = null

  return (...args: Parameters<T>) => {
    if (timeout) clearTimeout(timeout)
    timeout = setTimeout(() => {
      func(...args)
    }, wait)
  }
}

/**
 * 节流函数
 * @param func 要节流的函数
 * @param wait 等待时间（毫秒）
 */
export const throttle = <T extends (...args: any[]) => any>(
  func: T,
  wait: number,
): ((...args: Parameters<T>) => void) => {
  let lastTime = 0

  return (...args: Parameters<T>) => {
    const now = Date.now()
    if (now - lastTime >= wait) {
      lastTime = now
      func(...args)
    }
  }
}

/**
 * 深度克隆
 * @param obj 要克隆的对象
 */
export const deepClone = <T>(obj: T): T => {
  if (obj === null || typeof obj !== 'object') return obj

  if (obj instanceof Date) return new Date(obj.getTime()) as any
  if (obj instanceof Array) return obj.map((item) => deepClone(item)) as any

  const clonedObj = {} as T
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      clonedObj[key] = deepClone(obj[key])
    }
  }

  return clonedObj
}

/**
 * 生成唯一ID
 * @returns 唯一ID字符串
 */
export const generateId = (): string => {
  return `${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
}

/**
 * 生成UUID
 * @returns UUID字符串
 */
export const generateUUID = (): string => {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
    const r = (Math.random() * 16) | 0
    const v = c === 'x' ? r : (r & 0x3) | 0x8
    return v.toString(16)
  })
}

/**
 * 数组去重
 * @param arr 数组
 */
export const unique = <T>(arr: T[]): T[] => {
  return Array.from(new Set(arr))
}

/**
 * 数组去重（根据指定字段）
 * @param arr 数组
 * @param key 字段名
 */
export const uniqueBy = <T extends Record<string, any>>(arr: T[], key: keyof T): T[] => {
  const seen = new Set()
  return arr.filter((item) => {
    const value = item[key]
    if (seen.has(value)) return false
    seen.add(value)
    return true
  })
}

/**
 * 数组分组
 * @param arr 数组
 * @param key 分组字段
 */
export const groupBy = <T extends Record<string, any>>(arr: T[], key: keyof T): Record<string, T[]> => {
  return arr.reduce(
    (result, item) => {
      const groupKey = String(item[key])
      if (!result[groupKey]) result[groupKey] = []
      result[groupKey].push(item)
      return result
    },
    {} as Record<string, T[]>,
  )
}

/**
 * 数组分块
 * @param arr 数组
 * @param size 每块大小
 */
export const chunk = <T>(arr: T[], size: number): T[][] => {
  const result: T[][] = []
  for (let i = 0; i < arr.length; i += size) {
    result.push(arr.slice(i, i + size))
  }
  return result
}

/**
 * 对象合并（深度）
 * @param target 目标对象
 * @param sources 源对象
 */
export const deepMerge = <T extends Record<string, any>>(target: T, ...sources: Partial<T>[]): T => {
  if (!sources.length) return target

  const source = sources.shift()
  if (!source) return target

  for (const key in source) {
    const sourceValue = source[key]
    const targetValue = target[key]

    if (
      sourceValue &&
      typeof sourceValue === 'object' &&
      !Array.isArray(sourceValue) &&
      targetValue &&
      typeof targetValue === 'object' &&
      !Array.isArray(targetValue)
    ) {
      target[key] = deepMerge(targetValue, sourceValue)
    } else {
      target[key] = sourceValue as any
    }
  }

  return deepMerge(target, ...sources)
}

/**
 * 获取URL参数
 * @param url URL字符串
 */
export const getUrlParams = (url: string): Record<string, string> => {
  const params: Record<string, string> = {}
  const queryString = url.split('?')[1]

  if (!queryString) return params

  queryString.split('&').forEach((param) => {
    const [key, value] = param.split('=')
    if (key) {
      params[decodeURIComponent(key)] = decodeURIComponent(value || '')
    }
  })

  return params
}

/**
 * 构建URL参数
 * @param params 参数对象
 */
export const buildUrlParams = (params: Record<string, any>): string => {
  return Object.keys(params)
    .filter((key) => params[key] !== undefined && params[key] !== null)
    .map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(String(params[key]))}`)
    .join('&')
}

/**
 * 格式化文件大小
 * @param bytes 字节数
 * @param decimals 小数位数
 */
export const formatFileSize = (bytes: number, decimals: number = 2): string => {
  if (bytes === 0) return '0 Bytes'

  const k = 1024
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))

  return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i]
}

/**
 * 获取文件扩展名
 * @param filename 文件名
 */
export const getFileExtension = (filename: string): string => {
  return filename.split('.').pop()?.toLowerCase() || ''
}

/**
 * 截取字符串（超出部分显示省略号）
 * @param str 字符串
 * @param maxLength 最大长度
 * @param suffix 后缀
 */
export const truncate = (str: string, maxLength: number, suffix: string = '...'): string => {
  if (str.length <= maxLength) return str
  return str.substring(0, maxLength - suffix.length) + suffix
}

/**
 * 首字母大写
 * @param str 字符串
 */
export const capitalize = (str: string): string => {
  if (!str) return ''
  return str.charAt(0).toUpperCase() + str.slice(1)
}

/**
 * 驼峰转下划线
 * @param str 字符串
 */
export const camelToSnake = (str: string): string => {
  return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`)
}

/**
 * 下划线转驼峰
 * @param str 字符串
 */
export const snakeToCamel = (str: string): string => {
  return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
}

/**
 * 随机数（指定范围）
 * @param min 最小值
 * @param max 最大值
 */
export const randomInt = (min: number, max: number): number => {
  return Math.floor(Math.random() * (max - min + 1)) + min
}

/**
 * 随机选择数组元素
 * @param arr 数组
 */
export const randomPick = <T>(arr: T[]): T => {
  return arr[randomInt(0, arr.length - 1)]
}

/**
 * 打乱数组
 * @param arr 数组
 */
export const shuffle = <T>(arr: T[]): T[] => {
  const result = [...arr]
  for (let i = result.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1))
    ;[result[i], result[j]] = [result[j], result[i]]
  }
  return result
}

/**
 * 重试函数
 * @param fn 要重试的函数
 * @param maxRetries 最大重试次数
 * @param delay 重试延迟（毫秒）
 */
export const retry = async <T>(fn: () => Promise<T>, maxRetries: number = 3, delay: number = 1000): Promise<T> => {
  let lastError: any

  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn()
    } catch (error) {
      lastError = error
      if (i < maxRetries - 1) {
        await sleep(delay)
      }
    }
  }

  throw lastError
}

/**
 * 安全的JSON解析
 * @param str JSON字符串
 * @param defaultValue 默认值
 */
export const safeJsonParse = <T = any>(str: string, defaultValue: T | null = null): T | null => {
  try {
    return JSON.parse(str)
  } catch {
    return defaultValue
  }
}

/**
 * 手机号脱敏
 * @param phone 手机号
 */
export const maskPhone = (phone: string): string => {
  if (!phone || phone.length !== 11) return phone
  return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
}

/**
 * 身份证号脱敏
 * @param idCard 身份证号
 */
export const maskIdCard = (idCard: string): string => {
  if (!idCard || idCard.length < 8) return idCard
  return idCard.replace(/(\d{6})\d+(\d{4})/, '$1********$2')
}

/**
 * 银行卡号脱敏
 * @param bankCard 银行卡号
 */
export const maskBankCard = (bankCard: string): string => {
  if (!bankCard || bankCard.length < 8) return bankCard
  return bankCard.replace(/(\d{4})\d+(\d{4})/, '$1 **** **** $2')
}

/**
 * 解析Cookie字符串，提取指定名称的cookie值
 * @param cookieString Cookie字符串
 * @param name Cookie名称
 * @returns Cookie值，如果不存在则返回null
 */
export const parseCookie = (cookieString: string, name: string): string | null => {
  if (!cookieString || !name) return null

  // 使用正则表达式匹配指定名称的cookie
  const regex = new RegExp(`(?:^|;\\s*)${name}=([^;]*)`)
  const match = cookieString.match(regex)

  return match ? decodeURIComponent(match[1]) : null
}

/**
 * 解析Cookie字符串，提取auth-token的值
 * @param cookieString Cookie字符串
 * @returns auth-token的值，如果不存在则返回null
 */
export const getAuthToken = (cookieString: string): string | null => {
  return parseCookie(cookieString, 'auth-token')
}

export default {
  // 时间工具
  sleep,

  // 函数工具
  debounce,
  throttle,
  retry,

  // 对象工具
  deepClone,
  deepMerge,

  // ID生成
  generateId,
  generateUUID,

  // 数组工具
  unique,
  uniqueBy,
  groupBy,
  chunk,
  shuffle,
  randomPick,

  // URL工具
  getUrlParams,
  buildUrlParams,

  // 文件工具
  formatFileSize,
  getFileExtension,

  // 字符串工具
  truncate,
  capitalize,
  camelToSnake,
  snakeToCamel,
  maskPhone,
  maskIdCard,
  maskBankCard,

  // 随机数工具
  randomInt,

  // 其他
  safeJsonParse,
}
